package domain.shop;

import domain.AbstractEntity;
import domain.cms.CmsAttribute;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;

import javax.persistence.*;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlTransient;
import java.util.*;

@Entity
@Table(name = "Category")
@NamedQueries({
        @NamedQuery(name = "Category.findByTitle",
                query = "FROM Category WHERE attribute.title LIKE :title"),
        @NamedQuery(name = "Category.findChildsByParentId",
                query = "FROM Category WHERE parent.id = :parentId"),
        @NamedQuery(name = "Category.findRoots",
                query = "FROM Category WHERE parent is NULL")
})
public class Category extends AbstractEntity implements Comparable {

    @OneToOne
    @Cascade(CascadeType.ALL)

    CmsAttribute attribute = new CmsAttribute();
    @ManyToMany
    private Set<Product> products = new HashSet<Product>();
    @ManyToOne
    private Category parent;
    @OneToMany(mappedBy = "parent")
    @Cascade(value = CascadeType.DELETE_ORPHAN)
    private List<Category> childs = new ArrayList<Category>();
    private String name = "";

    public Category() {
    }

    public Category(String name) {
        this.name = name;
        attribute.setTitle(name);
    }

    public void afterUnmarshal(Unmarshaller u, Object parent) {
        this.parent = (Category) parent;
    }

    @XmlAttribute
    public String getName() {
        return name;
    }

    /**
     * Set Name and title
     *
     * @param name
     */
    public void setName(String name) {
        this.name = name;
        attribute.setTitle(name);
    }

    @XmlTransient
    public Category getParent() {
        return parent;
    }

    public void setParent(Category parent) {
        this.parent = parent;
    }

    public List<Category> getChilds() {
        return childs;
    }

    public void setChilds(List<Category> descendants) {
        this.childs = descendants;
    }

    /**
     * Set name and title
     *
     * @param title
     */
    public void setTitle(String title) {
        attribute.setTitle(title);
        this.name = title;
    }

    public void setKeywords(String keywords) {
        attribute.setKeywords(keywords);
    }

    public void setDescription(String description) {
        attribute.setDescription(description);
    }

    public void setContent(String content) {
        attribute.setContent(content);
    }

    public String getTitle() {
        return attribute.getTitle();
    }

    public Date getLastEditedDate() {
        return attribute.getLastEditedDate();
    }

    public String getKeywords() {
        return attribute.getKeywords();
    }

    public String getDescription() {
        return attribute.getDescription();
    }

    public String getContent() {
        return attribute.getContent();
    }

    public Set<Product> getProducts() {
        return products;
    }

    @XmlTransient
    public void setProducts(Set<Product> products) {
        this.products = products;
    }

    @Override
    public String toString() {
        return (getTitle() + " (Id:" + getId() + ")");
    }

    public void removeProduct(Product product) {
        getProducts().remove(product);
    }

    public void addProduct(Product product) {
        getProducts().add(product);
    }

    public int compareTo(Object o) {
        if (!(o instanceof Category)) {
            throw new ClassCastException("A Category object expected.");
        }
        Long newId = ((Category) o).getId();
        return (int) (this.getId() - newId);
    }

    @Override
    public boolean equals(Object o) {
        if (!(o instanceof Category)) {
            return false;
        }
        Long newId = ((Category) o).getId();
        if (this.getId().equals(newId) && this.hashCode() == o.hashCode()) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 83 * hash + (this.attribute != null ? this.attribute.hashCode() : 0);

        hash = 83 * hash + (this.name != null ? this.name.hashCode() : 0);
        return hash;
    }
}

